﻿/*
Copyright © 2011 François Karman

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

See <license.txt> for the complete license of the software.
*/

using System;
using System.Collections.Generic;

namespace Simple.Storage.Api
{
    /// <summary>
    /// Implements the <see cref="IDescriptor{T}"/> interface.
    /// </summary>
    /// <typeparam name="T">The associated persisted class.</typeparam>
    /// <seealso cref="IndexManager"/>
    internal class GenericDescriptor<T> : IDescriptor<T>
    {
        /// <summary>
        /// The encapsulated non-generic descriptor.
        /// </summary>
        private readonly IndexManagerNode encapsulated;

        /// <summary>
        /// The method used to get the value.
        /// </summary>
        private readonly Func<T> getValue;

        /// <summary>
        /// The loaded value.
        /// </summary>
        private T value;

        /// <summary>
        /// A value indicating whether the <see cref="GenericDescriptor{T}.value"/>
        /// has been loaded.
        /// </summary>
        private bool initialized;

        /// <summary>
        /// Initializes a new instance of the GenericDescriptor class.
        /// </summary>
        /// <param name="encapsulated">The encapsulated non-generic descriptor.</param>
        /// <param name="getValue">The method used to get the value.</param>
        public GenericDescriptor(IndexManagerNode encapsulated, Func<T> getValue)
        {
            if (encapsulated == null)
            {
                throw new ArgumentNullException("encapsulated");
            }
            else if (getValue == null)
            {
                throw new ArgumentNullException("getValue");
            }

            this.encapsulated = encapsulated;
            this.getValue = getValue;
        }

        /// <summary>
        /// Gets the associated persisted class.
        /// </summary>
        public Type ClassType
        {
            get { return typeof(T); }
        }

        /// <summary>
        /// Gets the key of the instance.
        /// </summary>
        public object Key
        {
            get { return this.encapsulated.Key; }
        }

        /// <summary>
        /// Gets the index values of the instance for each known index.
        /// </summary>
        public IDictionary<string, object> Index
        {
            get { return this.encapsulated.Index; }
        }

        /// <summary>
        /// Gets the associated persisted instance.
        /// </summary>
        public T Value
        {
            get
            {
                if (!this.initialized)
                {
                    this.value = this.getValue();
                    this.initialized = true;
                }

                return this.value;
            }
        }
    }
}
